﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Data;
using System.Configuration;
using System.Data.Objects;
using MoneyManagerNET.Model;

namespace MoneyManagerNET.DAL.Repository.EF4.SqlCe
{
    public class EntityBus:IEntityBus
    {
        static TraceSource trace = new TraceSource("storage");




        public EntityBus()
        {
            
            trace.TraceEvent(TraceEventType.Information, 0, "EntityFramework.EntityBus");
            EntityFrameworkContext = new TrecableObjectContext();
            EntityFrameworkContext.CommandTimeout = 0;//SqlCe will crush without this
            EntityFrameworkContext.ObjectMaterialized += (s, e) => { trace.TraceInformation("materialized: {0}",e.Entity); };
            EntityFrameworkContext.SavingChanges += (s, e) => { trace.TraceInformation("saving changes: added:{0}   edited:{1}  deleted:{2}",
                EntityFrameworkContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Count(),
                EntityFrameworkContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Count(),
                EntityFrameworkContext.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted).Count()); };



            //only works for one user scenarios
            MaxTransactionId = (from tran in EntityFrameworkContext.TransactionSet select tran.Id).OrderBy(i=>i).FirstOrDefault();
            MaxCategoryId = (from i in EntityFrameworkContext.CategorySet select i.Id).OrderBy(i=>i).FirstOrDefault();
            MaxSubcategoryId = (from i in EntityFrameworkContext.SubCategorySet select i.Id).OrderBy(i=>i).FirstOrDefault();
            MaxAccountId = (from i in EntityFrameworkContext.AccountSet where i is BankAccount  select i.Id).OrderBy(i=>i).FirstOrDefault();
            MaxContragentId = (from i in EntityFrameworkContext.ContragentSet select i.Id).OrderBy(i=>i).FirstOrDefault();
            MaxStockInvestmentId = (from i in EntityFrameworkContext.StockInvestmentSet select i.Id).OrderBy(i => i).FirstOrDefault();
            MaxAssetId = (from i in EntityFrameworkContext.AssetSet select i.Id).OrderBy(i => i).FirstOrDefault();
        }





        SqlCeModelContainer EntityFrameworkContext = null;

        public IEnumerable<TEntity> Select<TEntity>(Func<TEntity, bool> where) where TEntity : class
        {
            trace.TraceInformation("EntityFramework Select {0}", typeof(TEntity).Name);

            var baseQuery=SelectListByType<TEntity>();
            
            var result=where == null ? baseQuery : baseQuery.Where(where);

            trace.TraceData(TraceEventType.Information, 0, result);


            //var oq = result as ObjectQuery;
            //trace.TraceInformation(oq.CommandText);

            return result;
        }




        private IEnumerable<TEntity> SelectListByType<TEntity>() where TEntity : class
        {
            System.Collections.IEnumerable e = null;
            if (typeof(TEntity) == typeof(Model.ITransaction)) e = EntityFrameworkContext.TransactionSet.Include("Category").Include("SubCategory").Include("Contragent");
            if (typeof(TEntity) == typeof(Model.ISubCategory)) e = EntityFrameworkContext.SubCategorySet;
            if (typeof(TEntity) == typeof(Model.ICategory)) e = EntityFrameworkContext.CategorySet.Include("SubCategoryList"); 
            if (typeof(TEntity) == typeof(Model.IStockInvestment)) e = EntityFrameworkContext.StockInvestmentSet;
            if (typeof(TEntity) == typeof(Model.IStockAccount)) e = EntityFrameworkContext.AccountSet.Where(acc=>acc is StockAccount);
            if (typeof(TEntity) == typeof(Model.ICurrency)) e = EntityFrameworkContext.CurrencySet;
            if (typeof(TEntity) == typeof(Model.IContragent)) e = EntityFrameworkContext.ContragentSet;
            if (typeof(TEntity) == typeof(Model.IBankAccount)) e = EntityFrameworkContext.AccountSet.Where(acc => acc is BankAccount);
            if (typeof(TEntity) == typeof(Model.IAccount)) e = EntityFrameworkContext.AccountSet;
            if (typeof(TEntity) == typeof(Model.IAsset)) e = EntityFrameworkContext.AssetSet;

            var oq = e as ObjectQuery;
            if (oq != null) trace.TraceInformation( oq.ToTraceString());
            return e.Cast<TEntity>();
        }





        int MaxAccountId;
        int MaxTransactionId;
        int MaxCategoryId;
        int MaxSubcategoryId;
        int MaxContragentId;
        int MaxCurrencyId;
        int MaxStockInvestmentId;
        int MaxAssetId;

        public TEntity New<TEntity>() where TEntity : class
        {
            trace.TraceInformation("New {0}",typeof(TEntity).Name);
            object e = null;
            if (typeof(TEntity) == typeof(Model.ITransaction))
            {
                var item=EntityFrameworkContext.CreateObject<Transaction>();
                item.Id = ++MaxTransactionId;
                EntityFrameworkContext.TransactionSet.AddObject(item);
                e = item;
            }

            if (typeof(TEntity) == typeof(Model.ISubCategory))
            {
                var item = EntityFrameworkContext.CreateObject<SubCategory>();
                item.Id = ++MaxSubcategoryId;
                EntityFrameworkContext.SubCategorySet.AddObject(item);
                e = item;
            }

            if (typeof(TEntity) == typeof(Model.ICategory))
            {
                var item = EntityFrameworkContext.CreateObject<Category>();
                item.Id = ++MaxCategoryId;
                EntityFrameworkContext.CategorySet.AddObject(item);
                e = item;
            }

            if (typeof(TEntity) == typeof(Model.IStockInvestment))
            {
                var item = EntityFrameworkContext.CreateObject<StockInvestment>();
                item.Id = ++MaxStockInvestmentId;
                EntityFrameworkContext.StockInvestmentSet.AddObject(item);
                e = item;
            }


            if (typeof(TEntity) == typeof(Model.IStockAccount))
            {
                var item = EntityFrameworkContext.CreateObject<StockAccount>();
                item.Id = ++MaxAccountId;
                EntityFrameworkContext.AccountSet.AddObject(item);
                e = item;
            }

            if (typeof(TEntity) == typeof(Model.ICurrency))
            {                
                e = EntityFrameworkContext.CreateObject<Currency>();
                EntityFrameworkContext.CurrencySet.AddObject((Currency)e);
            }

            if (typeof(TEntity) == typeof(Model.IContragent))
            {
                var item = EntityFrameworkContext.CreateObject<Contragent>();
                item.Id = ++MaxContragentId;
                EntityFrameworkContext.ContragentSet.AddObject(item);
                e = item;
            }

            if (typeof(TEntity) == typeof(Model.IBankAccount))
            {
                var item = EntityFrameworkContext.CreateObject<BankAccount>();
                item.Id = ++MaxAccountId;
                EntityFrameworkContext.AccountSet.AddObject(item);
                e = item;
            }


            if (typeof(TEntity) == typeof(Model.IAccount))
            {
                var item = EntityFrameworkContext.CreateObject<Account>();
                item.Id = ++MaxAccountId;
                EntityFrameworkContext.AccountSet.AddObject(item);
                e = item;
            }

            if (typeof(TEntity) == typeof(Model.IAsset))
            {
                var item = EntityFrameworkContext.CreateObject<Asset>();
                item.Id = ++MaxAssetId;
                EntityFrameworkContext.AssetSet.AddObject(item);
                e = item;
            }


            trace.TraceInformation("there are {0} ne objects ",this.EntityFrameworkContext.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).Count());
            return e as TEntity;
        }

        public void Delete<TEntity>(TEntity entity) where TEntity : class
        {
            trace.TraceInformation("EntityFramework Deleting object");
            EntityFrameworkContext.DeleteObject(entity);
        }

        public void SaveAll()
        {

            //weired but works
            //I get exception on first try to open connection
            //Handle is not initialized.  Void OpenStoreConnectionIf
            try { EntityFrameworkContext.Connection.Open(); }
            catch { }

            try
            {
                EntityFrameworkContext.SaveChanges();
            }
            catch (Exception exp) { 
                trace.TraceEvent(TraceEventType.Error,0,"ERROR: EntityFramework SaveAll :{0}",exp.Message);
            }
        }

        public void Reset()
        {
            throw new NotImplementedException();
        }
    }
}
